home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
boot
/
czesc_2
/
saferpatches
/
source.lha
/
Source
/
SaferPatches.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-04
|
11KB
|
281 lines
/**************************************************************************/
/* Discription: */
/* The exec.library SetFunction function is very unsafe to use when */
/* more than one program changes a function in a library. */
/* */
/* The programs must change the function back in reverse order. */
/* */
/* example: */
/* Two different programs (A & B) changes the DisplayBeep function */
/* in intuition.library. */
/* */
/*------------- First both programs changes the function ----------------*/
/* A: A_OldFunc = SetFunction(IntuitionBase,_LVODisplayBeep,A_DispBeep);*/
/* A_OldFunc will contain the original position of DisplayBeep. */
/* */
/* B: B_OldFunc SetFunction(IntuitionBase,_LVODisplayBeep,B_DispBeep); */
/* B_OldFunc will contain the position of A_DispBeep. */
/* */
/*---- Then both programs restores the function (In wrong order)---------*/
/* A: SetFunction(IntuitionBase, _LVODisplayBeep; A_OldFunc) */
/* The original DisplayBeep function will be restored. */
/* (B_DispBeep will not be called) */
/* */
/* B: SetFunction(IntuitionBase, _LVODisplayBeep; B_OldFunc) */
/* The function A_DispBeep will be started again. */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* (If program A is no longer present the guru comes when */
/* someone calls the DisplayBeep function.) */
/* */
/* This program fixes these problems in a fully tranparent way */
/* */
/**************************************************************************/
/**************************************************************************/
/* LibHeader */
/* NextLib: Next library in a linked list. */
/* LibBase: Pointer to the libraries base (e.g. intuitionbase). */
/* Patches: Pointer to linked list of patches made to this library. */
/**************************************************************************/
struct LibHeader {
struct Library *LibBase;
struct Patches *Patches;
struct LibHeader *NextLib;
};
/************************************************************************/
/* Patches */
/* JMP : Opcode for JMP (used to call the old function). */
/* OldFunc : Address to the previus function (before SetFunction). */
/* NewFunc : The new function. */
/* Offset : Offset in library (Must be negativ). */
/* NextPatch: Pointer to next patch in list. */
/* */
/* The first Patch in the library list is just a dummy, */
/* Offset = MAGIC_OFFSET (makes the code more simple). */
/* After the dummy comes all patches made to this library sorted after */
/* their Offset (lowest value first). If there are more then one patch */
/* at one offset, the most recent comes first. */
/************************************************************************/
struct Patches {
USHORT JMP;
LONG OldFunc;
LONG NewFunc;
SHORT Offset;
struct Patches *NextPatch;
};
/******* Some useful defines ********/
/* This offset identifies our dummy patch */
#define MAGIC_OFFSET 123
/* Kickstart library versions */
#define KS13 35
/*************/
#define AND &&
#define OR ||
/************* Functions ****************/
/* A0 A1 D0 */
STATIC LONG NewSetFunction(APTR Offset, struct Library *Library, LONG NewFunc);
extern LONG OldSetFunction(APTR Offset, struct Library *Library, LONG NewFunc);
struct LibHeader *MakeHead(struct Library *Library);
STATIC struct Patches *MakePatch(APTR Offset, struct Patches *Next, LONG NewFunc);
/************* Global variables **********/
extern struct DosBase *DOSBase; /* Must be first */
extern struct SignalSemaphore SetFuncSemaphore;
extern struct LibHeader *MainHeader;
extern __fptr OldSetFuncPtr;
/*************************************************/
/* NewSetFunction: Replaces the exec SetFunction */
/*************************************************/
LONG NewSetFunction(APTR Offset, struct Library *Library, LONG NewFunc) /* D0 */
{
struct LibHeader *HeadPtr, *HeadPtr1;
struct Patches *Patch;
LONG OldFunc = NULL;
geta4();
/* old dos.library can't be handled here */
if (Library == DOSBase AND Library->lib_Version <= KS13)
return OldSetFunction(Offset, Library, NewFunc);
/* Be sure no one else is using the patch list */
ObtainSemaphore(&SetFuncSemaphore);
HeadPtr = MainHeader;
while (HeadPtr1 = HeadPtr->NextLib) {
/************************/
/* Find the library */
/************************/
if (HeadPtr1->LibBase == Library) {
Patch = HeadPtr1->Patches;
FOREVER { /* We leave this loop with goto */
/*******************************************/
/* Look through the sorted list of patches */
/*******************************************/
struct Patches *Patch1 = Patch->NextPatch;
if (Patch1 == NULL OR Patch1->Offset < (WORD)Offset) {
/****************************************/
/* No patch at this offset is installed */
/* Make a new one. */
/****************************************/
Patch1 = MakePatch(Offset, Patch1, NewFunc);
if (Patch1)
if (Patch1->OldFunc = OldSetFunction(Offset, Library, NewFunc))
OldFunc = (LONG)(Patch->NextPatch = Patch1);
else /* SetFunction failed */
FreeMem(Patch1,sizeof(struct Patches));
goto Done; /******************************/
}
if (Patch1->Offset == (WORD)Offset) {
/***************************************/
/* There are patches already installed */
/* Find out if anyone is to be removed */
/***************************************/
struct Patches *Patch2;
/********************************************************/
/* Some tasks don't care about the data returned from */
/* SetFunction (e.g. Xoper), instead they look directly */
/* into library structure to find the old function. */
/* Since this is bad programming we can't do much about */
/* it. If we are lucky no other patches are made to */
/* the same offset. */
/********************************************************/
if ((LONG)Patch1 == NewFunc OR Patch1->OldFunc == NewFunc) {
/*******************************************************/
/* User want's to remove the last (or only) made patch */
/* This is easy, just remove it */
/*******************************************************/
OldFunc = OldSetFunction(Offset, Library, Patch1->OldFunc);
if (OldFunc == Patch1->NewFunc) {
Patch->NextPatch = Patch1->NextPatch;
FreeMem(Patch1,sizeof(struct Patches));
}
else {
/******************************************************/
/* If we gets here something is very wrong */
/* Either has someone managed to change the vector */
/* from the outside (Virus !?) or SetFunction failed */
/* for some strange reason. */
/* We just restore the vector and hopes for the best. */
/******************************************************/
if (OldFunc) {
OldSetFunction(Offset, Library, OldFunc);
OldFunc = NULL;
}
goto Done;
}
/**************************************************/
/* If this was the last patch made to the library */
/* Release unused memory. */
/**************************************************/
if (Patch->Offset == MAGIC_OFFSET AND
Patch->NextPatch == NULL) {
HeadPtr->NextLib = HeadPtr1->NextLib;
FreeMem(Patch,sizeof(struct Patches));
FreeMem(HeadPtr1,sizeof(struct LibHeader));
}
goto Done; /******************************/
}
/********************************************************/
/* Are there any more patches made to the same offset ? */
/********************************************************/
while ((Patch2 = Patch1->NextPatch) AND
Patch2->Offset == (WORD)Offset) {
if ((LONG)Patch2 == NewFunc OR Patch2->OldFunc == NewFunc) {
/*****************************************************/
/* The user want's to remove an older patched */
/* This is more tricky, must restore OldFunc pointer */
/*****************************************************/
Patch1->NextPatch = Patch2->NextPatch;
Patch1->OldFunc = Patch2->OldFunc;
OldFunc = Patch2->NewFunc; /* No SetFunction here !! */
FreeMem(Patch2,sizeof(struct Patches));
goto Done; /******************************/
}
Patch1 = Patch2;
}
/*****************************************/
/* This was a new patch which takes over */
/*****************************************/
Patch1 = MakePatch(Offset, Patch->NextPatch, NewFunc);
if (Patch1)
if (Patch1->OldFunc = OldSetFunction(Offset, Library, NewFunc))
OldFunc = (LONG)(Patch->NextPatch = Patch1);
else /* SetFunction failed */
FreeMem(Patch1,sizeof(struct Patches));
goto Done; /******************************/
} /* if (Patch1->Offset == ... */
/* Try next patch in list */
Patch = Patch1;
} /* FOREVER */
} /* if (HeadPtr->Lib ... */
/* try next library in list */
HeadPtr = HeadPtr1;
} /* while (HeadPtr1 = ... */
/***************/
/* New library */
/***************/
HeadPtr1 = HeadPtr->NextLib = MakeHead(Library);
/*******************/
/* Crete the patch */
/*******************/
if (HeadPtr1) {
if (Patch = MakePatch(Offset, NULL, NewFunc)) {
/* crete a dummy patch */
if (HeadPtr1->Patches = MakePatch((APTR)MAGIC_OFFSET, Patch, NULL)) {
if (Patch->OldFunc = OldSetFunction(Offset, Library, NewFunc)) {
HeadPtr->NextLib = HeadPtr1;
OldFunc = (LONG)Patch;
goto Done;
} /* SetFunction failed */
FreeMem(HeadPtr1->Patches,sizeof(struct Patches));
} /* Can't crete dummy patch */
FreeMem(Patch,sizeof(struct Patches));
} /* Can't crete real patch */
FreeMem(HeadPtr1,sizeof(struct LibHeader));
} /* Can't crete header */
Done:
ReleaseSemaphore(&SetFuncSemaphore);
return OldFunc;
}
struct LibHeader *MakeHead(struct Library *Library)
{
struct LibHeader *Head;
if (Head = AllocMem(sizeof(struct LibHeader),MEMF_CLEAR))
Head->LibBase = Library;
return Head;
}
struct Patches *MakePatch(APTR Offset, struct Patches *Next, LONG NewFunc)
{
struct Patches *Patch;
if (Patch = AllocMem(sizeof(struct Patches),MEMF_CLEAR)) {
Patch->JMP = 0x4ef9; /* JMP opcode */
Patch->NewFunc = NewFunc;
Patch->Offset = (WORD)Offset;
Patch->NextPatch = Next;
}
return Patch;
}